package com.zlzsy.app.base.utils

import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.util.Base64

import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable

@Suppress("UNCHECKED_CAST")
/**
 * Created by niantuo on 2016/10/26.
 * 存储，读取APP需要缓存的数据
 */

class DataPool {

    private lateinit var mContext: Context

    private lateinit var sp: SharedPreferences

    @JvmOverloads constructor(context: Context, dataCachePoolName: String = sDataCachePoolName) {
        this.mContext = context
        sp = mContext.getSharedPreferences(dataCachePoolName, Context.MODE_PRIVATE)
    }

    constructor(context: Context, multi: Boolean) {
        this.mContext = context
        if (multi)
            sp = mContext.getSharedPreferences(sDataCachePoolName,
                    Context.MODE_WORLD_READABLE or Context.MODE_MULTI_PROCESS)
    }


    /**
     * @param key
     * @param value
     * @return
     */
    fun putSerializable(key: String, value: Serializable?): Boolean {

        if (value == null) {
            remove(key)
            return true
        }

        val outputStream = ByteArrayOutputStream()
        var objectOutputStream: ObjectOutputStream? = null

        try {
            objectOutputStream = ObjectOutputStream(outputStream)
            objectOutputStream.writeObject(value)
            val base64String = Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT)
            sp.edit().putString(key, base64String).apply()
            return true
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            if (objectOutputStream != null) {
                try {
                    objectOutputStream.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }

            }
        }
        return false
    }

    fun putString(key: String, value: String) {
        sp.edit().putString(key, value).apply()
    }

    fun putInt(key: String, value: Int) {
        sp.edit().putInt(key, value).apply()
    }

    fun putLong(key: String, vaule: Long) {
        sp.edit().putLong(key, vaule).apply()
    }

    fun putBoolean(key: String, value: Boolean) {
        sp.edit().putBoolean(key, value).apply()
    }

    fun putFloat(key: String, value: Float) {
        sp.edit().putFloat(key, value).apply()
    }


    fun putStringSet(key: String, values: Set<String>) {
        sp.edit().putStringSet(key, values).apply()
    }


    fun <T> getSerializable(key: String): T? {
        if (!contains(key)) return null

        val base64String = sp.getString(key, "")

        val bytes = Base64.decode(base64String, Base64.DEFAULT)
        val byteArrayInputStream = ByteArrayInputStream(bytes)
        var objectInputStream: ObjectInputStream? = null
        try {
            objectInputStream = ObjectInputStream(byteArrayInputStream)
            return (objectInputStream.readObject() as? T)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            if (objectInputStream != null) {
                try {
                    objectInputStream.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }

            }
        }
        return null
    }


    fun getString(key: String, defValue: String): String? = sp.getString(key, defValue)

    fun getBoolean(key: String, defValue: Boolean): Boolean = sp.getBoolean(key, defValue)


    fun getInt(key: String, defValue: Int): Int = sp.getInt(key, defValue)

    fun getFloat(key: String, defValue: Float): Float = sp.getFloat(key, defValue)

    fun getLong(key: String, defValue: Long): Long = sp.getLong(key, defValue)


    fun remove(key: String) {
        if (contains(key)) {
            sp.edit()
                    .remove(key)
                    .apply()
        }
    }

    fun removeAll() {
        val map = sp.all
        for (key in map.keys) {
            remove(key)
        }
    }

    private operator fun contains(key: String): Boolean = sp.contains(key)

    fun setSerializable(key: String, value: Serializable): Boolean =
            !contains(key) && putSerializable(key, value)

    companion object {

        private val sDataCachePoolName = "DataPool"
        private val sDataCustomPoolName = "Custom_DataPool"

        @SuppressLint("StaticFieldLeak")
        private var dataPool: DataPool? = null

        /**
         * 用户私有数据的数据保存，加上用户的ID，如果没有登录则不能读取
         *
         * @param context
         * @param userId
         * @return
         */
        fun getCustomCache(context: Context, userId: String): DataPool {
            if (dataPool == null) {
                dataPool = DataPool(context, sDataCustomPoolName + userId)
            }
            return dataPool!!
        }
    }

}
